package com.winning.xffw.service.quartz.manage.service.impl;

import com.winning.xffw.service.quartz.entity.QuartzJob;
import com.winning.xffw.service.quartz.manage.service.IJobManageService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * @Author: shipengfei
 * @Description:
 * @Date: 2019-06-03 17:43
 */
@Slf4j
@Service
public class JobManageServiceImpl implements IJobManageService {

    private static final String TRIGGER_IDENTITY = "trigger";
    private static final String PARAM_NAME = "paramName";
    private static final String PARAM_VALUE = "paramValue";
    private static final String SCHEDULER_INSTANCE_NAME = "schedulerInstanceName";

    @Value("${spring.quartz.properties.org.quartz.scheduler.instanceName}")
    private String schedulerInstanceName;

    @Autowired
    private Scheduler scheduler;

    /**
     * 新增、修改定时任务
     *
     * @param quartz
     */
    @Override
    public void saveJob(QuartzJob quartz) {
        try {
            //如果是修改，先删除原有任务
            if ("1".equals(quartz.getEditFlag())) {
                JobKey key = new JobKey(quartz.getJobName(), quartz.getJobGroup());
                scheduler.deleteJob(key);
            }
            //构建job信息
            Class cls = Class.forName(quartz.getJobClassName());
            cls.newInstance();
            JobDetail job = JobBuilder.newJob(cls).withIdentity(quartz.getJobName(), quartz.getJobGroup())
                    .withDescription(quartz.getDescription()).build();
            putDataMap(job, quartz);

            // 触发时间点
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartz.getCronExpression().trim());
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity(TRIGGER_IDENTITY + quartz.getJobName(), quartz.getJobGroup())
                    .startNow().withSchedule(cronScheduleBuilder).build();
            //交由Scheduler安排触发
            scheduler.scheduleJob(job, trigger);
            log.info("新增定时任务成功！");
        } catch (Exception e) {
            log.error("新增定时任务失败:", e);
            throw new RuntimeException("新增定时任务失败！", e);
        }
    }

    private void putDataMap(JobDetail job, QuartzJob quartz) {
        // 将scheduler instanceName存入jobDataMap，方便业务job中进行数据库操作
        JobDataMap jobDataMap = job.getJobDataMap();
        jobDataMap.put(SCHEDULER_INSTANCE_NAME, schedulerInstanceName);

        List<Map<String, Object>> jobDataParam = quartz.getJobDataParam();
        if (jobDataParam == null || jobDataParam.isEmpty()) {
            return;
        }
        jobDataParam.forEach(jobData -> jobDataMap.put(String.valueOf(jobData.get(PARAM_NAME)), jobData.get(PARAM_VALUE)));
    }

    /**
     * 触发任务
     *
     * @param jobName
     * @param jobGroup
     */
    @Override
    public void triggerJob(String jobName, String jobGroup) {
        JobKey key = new JobKey(jobName, jobGroup);
        try {
            scheduler.triggerJob(key);
            log.info("触发定时任务成功！");
        } catch (SchedulerException e) {
            log.error("定时任务触发失败:", e);
            throw new RuntimeException("触发定时任务失败！", e);
        }
    }

    /**
     * 停止定时任务
     *
     * @param jobName
     * @param jobGroup
     */
    @Override
    public void pauseJob(String jobName, String jobGroup) {
        JobKey key = new JobKey(jobName, jobGroup);
        try {
            scheduler.pauseJob(key);
            log.info("停止定时任务成功！");
        } catch (SchedulerException e) {
            log.error("停止定时任务失败:", e);
            throw new RuntimeException("停止定时任务失败！", e);
        }
    }

    /**
     * 恢复定时任务
     *
     * @param jobName
     * @param jobGroup
     */
    @Override
    public void resumeJob(String jobName, String jobGroup) {
        JobKey key = new JobKey(jobName, jobGroup);
        try {
            scheduler.resumeJob(key);
            log.info("恢复定时任务成功！");
        } catch (SchedulerException e) {
            log.error("恢复定时任务失败:", e);
            throw new RuntimeException("恢复定时任务失败！", e);
        }
    }
}
